<template>
  <!--工具条-->
  <el-row class="tac">
    <el-col :span="5">
      <el-card class="box-card" style="margin: 5px;">
        <div slot="header" class="clearfix">
          <span>接口目录
            <el-button type="text" class="el-icon-edit" style="position:relative;right: 5px;top: -5px;float: right;" @click="addFunPage()">添加</el-button>
          </span>
        </div>
        <div class="component-item">
          <a-tree default-expand-all @select="onSelect" show-icon @rightClick="onRightClick" :tree-data="packageInterfaceData" :default-selected-keys="['0-0-0']">
            <a-icon slot="switcherIcon" type="down" />
            <a-icon slot="smile" type="home" />
            <a-icon slot="meh" type="folder" />
            <a-icon slot="custom" type="api" />
          </a-tree>
        </div>
      </el-card>
    </el-col>
    <el-col :span="19">
      <el-card class="box-card" style="margin: 5px;">
        <div class="component-item" style="margin:10px;">
          <div style="width: 100%">
            <a-tabs v-model="activeKey" default-active-key="1" @prevClick="callback" @nextClick="callback" type="editable-card" :hideAdd="true" @edit="onEdit">
              <a-tab-pane v-for="(item, index) in tabs" :key="item.callMethodCode" :closable="item.closable">
                <template v-if="index === 0">
                  <span slot="tab">
                    <a-icon type="home" />
                    {{ item.title }}
                  </span>
                  <div class="planetext">
                    <p>
                      Mybatis语法是个不错的语法，能够将实体与数据库紧密的结合在一起，减少了存贮过程，视图的编写，而且比存贮过程，视图更多元化，更强大,有人说Mybatis已经很成熟了，为什么自己还需要开发一套这个组件，第一：主要是因为Mybatis语法只能写在Mapping和Dao实体中，写在这里就必须要编译。第二：传入的Map实体不能是解析的。 </p>
                    <p> 我的Mybatis语法引擎能够动态解析Json实体，获取其属性值进行拼装SQL，那我将Mybatis语法配置提取到前端网页中，保存到数据库中，设置好两者约定好提交json实体结构， 然后封装一个通用Api接口提供调用，通过请求参数找到Mybatis配置信息，提交约定好的Json实体结构的数据，从而实现对数据库的各交互的一个万能接口。该模式去掉了我们平时开发的实体层，Service层，Dao层，能够实现60%的后端业务功能，配置好接口就可以立马使用，同时也解决了无码开发后端的编码问题。遇到复杂的逻辑需二开，也支持后端java代码的调用。
                    </p>
                    <p>
                      Mybatis语法引擎设计思路就是参照了Mybatis底层实现原理实现的，在编写时在Mybatis sql语法中约定提交的实体，约定的实体可以是任何JSON<br />
                      通过#{属性名}映射获取json的属性值.例如:{bb:"323",cc:"434",fff:'fdsf'} 配置获取bb的值，如：#{bb} 获取cc的值,如：#{cc}<br />
                      通过#{属性名.子属性名称}映射获取属性对应子属性值.例如:提交json为：{bb:{cc:"fdsfds"}} 想获取cc的值#{bb.cc}<br />
                      通过#{属性名[0].子属性}映射获取数组属性，第一行的子属性值。例如:提交json为：{bb:[{cc:'dsad'},{cc:'324'},{cc:'434'},{cc:'343'}]} 获取bb第一行cc的值，如:#{bb[0].cc}<br />
                      通过&lt;for forname='属性名'&gt;#{属性名[$index0].子属性} &lt;/for&gt; 通过循坏获取子属性数组中具体的子属性.例如：提交json为{bb:[{cc:'dsad'},{cc:'324'},{cc:'434'},{cc:'343'}]} 选循坏获取所有的cc &lt;for forname='bb'&gt; select *from table where column=#{bb[$index0].cc} &lt;/for&gt; <br />
                      &lt;sql param='ccc' &gt; select * from AA &lt;/sql&gt; 将sql语句查询的结果放入JSON实体对象属性ccc中，后面sql脚本就可以用#{ccc[0].子属性} 并做参数入值。<br />
                      &lt;sql test='ccc!=0 and ccc&gt;5' &gt;select * from AA&lt;/sql &gt; test属性也支持条件判断<br />
                      也支持#{A属性+B属性}，#{A属性*B属性}，#{A属性/B属性}，#{A属性-B属性}，#{A属性==''?B属性:A属性} 最基础的运算与三元表达式的支持。<br />
                      编写的Mybatis语法代码不是保存在xml中，而是保存在在数据库中，随时更改，随时生效。<br />
                      结合当前环境变量#{$user}当前登录对象，#{$user.userId} #{$user.userName} #{$user.realaname} #{$user.deptcode} #{$user.deptname} #{$user.organcode} #{$user.organname} #{$user.deptid} #{$user.organid}
                      #{$user.password} #{$user.phone} #{$user.avatar}<br /> </p>
                    <p>
                      <span class="title color3">#优点</span> <br />
                      1.可以节省了开发人员的各种实体编写，不同层级之间的调用，直接编写mybastis语法，目标功能实现，效率能够大大提升。<br />
                      2.可根据需求变化而变化，灵活更改对应接口，灵活性非常好<br />
                      3.后期运维，逻辑简单，响应速度非常快。<br />

                      5.迁移与重复非常方便，因为整个配置只有一张表，只要将一条数据迁移过去，功能就迁移过去了，与数据库的藕合性低。<br />
                      6.可以与java紧密结合起来，（前期使用配置开发，发现后期需求变变化到无法满足的地步，就需要二次开发，可在java代码中调用。）<br />

                    </p>
                    <p>
                      <span class="title color3">#扩展思维</span><br />
                      1. 系统之间接口的对接，接口返回的json格式是固定的，如何将接口数据对接我们系统中，结合定时任务的配置是可以完美解决，各种系统数据对接和输出，实现万能对接接口<br />
                      2. MQ队列，MQ队列接收也是实体JSON格式，也是可以完美解决各种数据的同步与数据处理入库<br />
                      3. 各种xls的导入，导入的模板固定，对应JSON格式也就固定，同样可以适应，实现万能数据导入、导出接口<br />
                      4. 各种Api接口的开发，Api接口提交JSON格式数据是固定的，如现在系统的各种功能开发就用到了该接口。<br />
                      5. 因为接口是一个组件，也可以支持各种接口微服务，服务器负载均衡部署。<br />

                    </p>
                  </div>
                </template>
                <template v-else>
                  <span slot="tab">
                    <nx-svg-icon class-name="'apiyun-icon'" icon-class="apiyun" slot="avatar" style=" width: 1em;height: 1em;    color: rgb(16, 142, 233);" />

                    {{ item.title }}
                  </span>
                  <apihelpdetail :apiid="item.id"></apihelpdetail>
                </template>
              </a-tab-pane>
            </a-tabs>
          </div>
        </div>
      </el-card>
    </el-col>
    <zhlDialog title="接口编辑" ref="apiconfiginfodialog" width="1060px" class="my-dialog">
      <apiconfigedit :apiId="apiId" :pageId="pageId" @confirm="apiConfigInfoconfirm" @close="$refs.apiconfiginfodialog.visible = false"></apiconfigedit>
    </zhlDialog>
    <zhlDialog title="类名编辑" ref="pagedialog" width="360px" class="my-dialog">
      <el-form ref="elForm" :model="formData" size="medium" label-width="50px">
        <el-form-item label="类名">
          <a-input v-model="formData.pageName" placeholder="类名" @input="accountInput" clearable :style="{ width: '100%' }"></a-input>
        </el-form-item>
        <el-form-item label="描述">
          <a-input type="textarea" v-model="formData.description" placeholder="请输入描述" :rows="2" :style="{ width: '100%' }"></a-input>
        </el-form-item>
        <el-form-item size="large">
          <el-button type="primary" @click="submitForm">提交</el-button>
          <el-button @click="$refs.pagedialog.visible = false">关闭</el-button>
        </el-form-item>
      </el-form>
    </zhlDialog>

    <v-contextmenu ref="apiMenu">
      <v-contextmenu-item @click="editFunPackageInterface">修改</v-contextmenu-item>
      <v-contextmenu-item @click="delFunPackageInterface">删除</v-contextmenu-item>
    </v-contextmenu>
    <v-contextmenu ref="pageMenu">
      <v-contextmenu-item @click="editFunPackage">修改</v-contextmenu-item>
      <v-contextmenu-item @click="delFunPackage">删除</v-contextmenu-item>
      <v-contextmenu-item @click="addFunPackageInterface">添加接口</v-contextmenu-item>
    </v-contextmenu>
  </el-row>
</template>

<script>
import {
  getPackageInterfaceInfo,
  addPackageInfo,
  delPackageInfo,
  editPackageInfo,
  deleteMappingApiConfig
} from '@/api/packageInterface'
import apihelpdetail from './apihelpdetail.vue'
import apiconfigedit from './apiconfigedit.vue'
import nxSvgIcon from '@/components/nx-svg-icon/index'
export default {
  data () {
    return {
      packageInterfaceData: [],
      apiId: 0,
      pageId: 0,
      formData: { pageName: '', description: '' },
      parentnode: {},
      selectnode: {},
      tabs: [{ title: '首页', id: 0, closable: false, callMethodCode: '0' }],
      activeKey: '0',
      selectcallMethodCode: ''
    }
  },
  components: { apihelpdetail, apiconfigedit, nxSvgIcon },
  methods: {
    onSelect (selectedKeys, info) {
      if (info.node.dataRef.typeName === 'api') {
        let isAdd = true
        for (let i = 0; i < this.tabs.length; i++) {
          if (
            this.tabs[i].callMethodCode === info.node.dataRef.callMethodCode
          ) {
            if (this.tabs.indexOf(info.node.dataRef) < 0) {
              this.tabs.splice(i, 1)
              this.tabs.push(info.node.dataRef)
            }
            this.activeKey = info.node.dataRef.callMethodCode
            isAdd = false
            break
          }
        }
        if (isAdd) {
          this.tabs.push(info.node.dataRef)
          this.activeKey = info.node.dataRef.callMethodCode
        }
      }
    },
    onRightClick ({ event, node }) {
      const answer = node._props.dataRef.anwer
      if (answer) {
        this.$refs.pageMenu.hide()
        this.answer = answer
        return
      }
      this.parentnode = null
      if (node.$parent.dataRef !== null && node.$parent.dataRef !== undefined) {
        this.parentnode = node.$parent.dataRef
      }
      this.selectnode = node.dataRef
      const postition = {
        top: event.pageY,
        left: event.pageX
      }
      this.$refs.pageMenu.hide()
      this.$refs.apiMenu.hide()
      switch (this.selectnode.slots.icon) {
        case 'meh':
          this.$refs.pageMenu.show(postition)
          break
        case 'custom':
          this.$refs.apiMenu.show(postition)
          break
        default:
          break
      }
    },
    callback (val) {
      console.log(val)
    },
    addFunPackageInterface () {
      this.pageId = this.selectnode.id
      this.apiId = -1
      this.selectcallMethodCode = ''
      this.$refs.apiconfiginfodialog.visible = true
    },
    editFunPackage () {
      this.formData = this.selectnode
      this.$refs.pagedialog.visible = true
    },
    editFunPackageInterface () {
      this.apiId = this.selectnode.id
      this.pageId = this.selectnode.parentId
      this.selectcallMethodCode = this.selectnode.callMethodCode
      this.$refs.apiconfiginfodialog.visible = true
    },
    updateTabs (id) {
      if (
        this.selectcallMethodCode !== undefined ||
        this.selectcallMethodCode !== ''
      ) {
        this.tabs.forEach(obj => {
          if (obj.callMethodCode === this.selectcallMethodCode) {
            obj.id = id
          }
        })
      }
    },
    apiConfigInfoconfirm (res) {
      this.updateTabs(res.data)
      this.$refs.apiconfiginfodialog.visible = false
      this.loadData()
    },
    delFunPackageInterface () {
      deleteMappingApiConfig(this.selectnode.id).then(res => {
        this.$message.success(res.msg)
        this.loadData()
      })
    },
    delFunPackage () {
      if (this.selectnode.children.length > 0) {
        this.$message.error('请先删除子项！')
        return false
      }
      delPackageInfo(this.selectnode.id).then(res => {
        this.$message.success(res.msg)
        this.loadData()
      })
    },
    loadData () {
      getPackageInterfaceInfo().then(res => {
        const parent = { key: '', children: [] }
        this.recombination(res.data, parent)
        this.packageInterfaceData = parent.children
      })
    },
    onEdit (targetKey, action) {
      if (action === 'remove') {
        for (let i = 0; i < this.tabs.length; i++) {
          if (this.tabs[i].callMethodCode === targetKey) {
            this.tabs.splice(i, 1)
            this.activeKey = '0'
            break
          }
        }
      }
    },
    recombination (treelist, parent) {
      for (let i = 0; i < treelist.length; i++) {
        const itemdata = {
          title: treelist[i].pageName,
          key: parent.key + '-' + treelist[i].fid,
          id: treelist[i].fid,
          parentId: treelist[i].parentId,
          name: treelist[i].pageName,
          pageName: treelist[i].pageName,
          description: treelist[i].description,
          typeName: treelist[i].typeName,
          callMethodCode: treelist[i].callMethodCode,
          slots: {
            icon: 'smile'
          },
          children: []
        }
        switch (treelist[i].typeName) {
          case 'page':
            itemdata.slots.icon = 'meh'
            break
          case 'api':
            itemdata.slots.icon = 'custom'
            break
          default:
            break
        }
        this.recombination(treelist[i].children, itemdata)
        parent.children.push(itemdata)
      }
    },
    addFunPage () {
      this.formData = {}
      this.formData.pageName = ''
      this.formData.description = ''
      this.$refs.pagedialog.visible = true
    },
    submitForm () {
      if (this.formData.pageName === '') {
        this.$message.error('包名不能为空！')
        return
      }
      if (this.formData.fid !== undefined) {
        editPackageInfo(this.formData).then(res => {
          this.$message.success(res.msg)
          this.$refs.pagedialog.visible = false
          this.loadData()
        })
      } else {
        addPackageInfo(this.formData).then(res => {
          console.log(res)
          this.$message.success('保存成功！')
          this.$refs.pagedialog.visible = false
          this.loadData()
        })
      }
    },
    accountInput (e) {
      const valstr = e.target.value
      const codeReg = new RegExp('[A-Za-z]+')
      const len = valstr.length
      let str = ''
      for (let i = 0; i < len; i++) {
        if (codeReg.test(valstr[i])) {
          str = str + valstr[i]
        }
      }
      e.target.value = str
      this.formData.pageName = str
    },
    SaveAs (rowitem) {
      console.log(rowitem)
    }
  },
  mounted () {
    this.loadData()
  }
}
</script>
<style scoped>
.el-card__body {
  padding-top: 5px;
  padding-right: 5px;
  padding-left: 0px;
  padding-bottom: 10px;
}
.el-card__header {
  padding: 10px 15px;
}
</style>

<style lang="less" scoped>
.planetext {
  font-size: 14px;
  color: #666;
  line-height: 28px;
}
.planetext .title {
  font-size: 16px;
}
.wrapper {
  display: flex;
  align-content: center;
  height: auto;
  padding-top: 6px;
  background-color: #fff;
  border-bottom: 1px solid #ccc;
  height: 35px;
  span {
    height: 18px;
    line-height: 18px;
    color: #333;
    font-weight: bold;
  }
  .left-block {
    width: 6px;
    height: 18px;
    margin-right: 6px;
    background-color: #409eff !important;
  }
}
</style>
